﻿using System;
using System.Linq;
using System.Reflection;
using Axial.DOM;

namespace Axial
{
	public static partial class CallHandler
	{
		[CallHandler(typeof(XmlHttpRequest))]
		private static string HandleXmlHttpRequest(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}
		
		[CallHandler(typeof(Arguments))]
		private static string HandleArguments(MethodInfo method, object called, object[] stack)
		{
			called = "arguments";
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(Function))]
		private static string HandleFunction(MethodInfo method, object called, object[] stack)
		{
			if (called is Function)
				called = "this";
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(Location))]
		private static string HandleLocation(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(Element))]
		private static string HandleElement(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(Document))]
		private static string HandleDocument(MethodInfo method, object called, object[] stack)
		{
			string pascalCase = method.Name.LowerFirstLetter();
			string propertyName = method.Name.Length > 4 ? method.Name.Substring(4).LowerFirstLetter() : string.Empty;

			if (method.Name == "get_URL")
				return string.Format("document.URL", propertyName);
			if (method.Name == "get_ScrollLeft")
				return "(document.documentElement.scrollLeft != null ? document.documentElement.scrollLeft : document.body.scrollLeft)";
			if (method.Name == "get_ScrollTop")
				return "(document.documentElement.scrollTop != null ? document.documentElement.scrollTop : document.body.scrollTop)";
			if (method.Name.StartsWith("get_"))
				return string.Format("document.{0}", propertyName);
			if (method.Name.StartsWith("set_"))
				return string.Format("document.{0} = {1}", propertyName, stack[0]);
			return string.Format("document.{0}({1})", pascalCase, stack[0]);
		}

		[CallHandler(typeof(Window))]
		private static string HandleWindow(MethodInfo method, object called, object[] stack)
		{
			if (method.Name == "SetTimeout")
				return string.Format("setTimeout({0}, {1})", JSWebTranslator.DissembleAction(stack[0]), stack[1]);
			if (method.Name == "SetInterval")
				return string.Format("setInterval({0}, {1})", JSWebTranslator.DissembleAction(stack[0]), stack[1]);
			if (method.Name == "Debugger")
				return "debugger";

			// firefox will show "undefined" as default answer if no second argument is given
			if (method.Name == "Prompt" && stack.Length == 1)
				stack = stack.Concat(new object[] { "''" }).ToArray();

			called = "window";
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(JSArray<Anchor>))]
		private static string HandleJSArrayAnchor(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}
		[CallHandler(typeof(JSArray<Element>))]
		private static string HandleJSArrayElement(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(JSObject<Element>))]
		private static string HandleJSCollectionElement(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}
		[CallHandler(typeof(JSObject<Image>))]
		private static string HandleJSCollectionImage(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(Image))]
		private static string HandleDOMImage(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(Anchor))]
		private static string HandleAnchor(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}

		[CallHandler(typeof(Event))]
		private static string HandleEvent(MethodInfo method, object called, object[] stack)
		{
			return StandardHandler(method, called, stack);
		}
	}
}
